//: [Previous](@previous)

import Foundation


// Bitwise NOT Operator

let initialBits: UInt8 = 0b00001111;
let invertedBits = ~initialBits  // equals 11110000


// Bitwise AND Operator

let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8  = 0b00111111
let middleFourBits = firstSixBits & lastSixBits  // equals 00111100


// Bitwise OR Operator

let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits  // equals 11111110


// Bitwise XOR Operator

let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits  // equals 00010001


// Bitwise Left and Right Shift Operators

let shiftBits: UInt8 = 4   // 00000100 in binary
shiftBits << 1             // 00001000
shiftBits << 2             // 00010000
shiftBits << 5             // 10000000
shiftBits << 6             // 00000000
shiftBits >> 2             // 00000001

let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16    // redComponent is 0xCC, or 204
let greenComponent = (pink & 0x00FF00) >> 8   // greenComponent is 0x66, or 102
let blueComponent = pink & 0x0000FF           // blueComponent is 0x99, or 153


// Overflow Operators

//var potentialOverflow = Int16.max
//potentialOverflow += 1      // error

var unsignedOverflow = UInt8.max
unsignedOverflow = unsignedOverflow &+ 1

unsignedOverflow = UInt8.min
unsignedOverflow = unsignedOverflow &- 1

var signedOverflow = Int8.min
signedOverflow = signedOverflow &- 1


// Precedence and Associativity

2 + 3 % 4 * 5


// Operator Methods

struct Vector2D {
    var x = 0.0, y = 0.0;
}

extension Vector2D {
    static func + (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D.init(x: left.x + right.x, y: left.y + right.y);
    }
}

let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
combinedVector.x
combinedVector.y


// Prefix and Postfix Operators

extension Vector2D {
    static prefix func - (vector: Vector2D) -> Vector2D {
        return Vector2D.init(x: -vector.x, y: -vector.y);
    }
}

let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
negative.x
negative.y
let alsoPositive = -negative;
alsoPositive.x
alsoPositive.y


// Compound Assignment Operators

extension Vector2D {
    static func += (left: inout Vector2D, right: Vector2D) {
        left = left + right;
    }
}

var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
original.x
original.y


// Equivalence Operators

extension Vector2D {
    static func == (left: Vector2D, right: Vector2D) -> Bool {
        return (left.x == right.x) && (left.y == right.y);
    }
    
    static func != (left: Vector2D, right: Vector2D) -> Bool {
        return !(left == right);
    }
}

let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
    print("These two vectors are equivalent.")
}


// Custom Operators

prefix operator +++;

extension Vector2D {
    static prefix func +++ (vector: inout Vector2D) -> Vector2D {
        vector += vector;
        return vector;
    }
}

var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
afterDoubling.x
afterDoubling.y


// Precedence for Custom Infix Operators

infix operator +-: AdditionPrecedence

extension Vector2D {
    static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
}

let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
plusMinusVector.x
plusMinusVector.y


